#pragma once
// MFSI BY ZERO123
#define MFSI_CALL __cdecl

#ifdef __cplusplus
extern "C" {
#endif
	struct IMemoryPath;
	typedef unsigned int ByteSize;
	typedef void (MFSI_CALL *IMemoryPathWriteCallBack)(void*, IMemoryPath*);

	// 内存文件系统接口
	struct IMemoryBytes
	{
		ByteSize size;
		const char* bytes;
	};
	
	typedef struct IMemoryBytes (MFSI_CALL* _ReadBytesFunc)(void*);
	typedef struct IMemoryPath (MFSI_CALL* _ParentFunc)(void*);
	typedef const char* (MFSI_CALL* _GetFileNameFunc)(void*);
	typedef const char* (MFSI_CALL* _GetPathFunc)(void*, char*);
	typedef bool (MFSI_CALL* _WriteBytesFunc)(void*, const IMemoryBytes*);
	typedef bool (MFSI_CALL* _IsFileFunc)(void*);
	typedef bool (MFSI_CALL* _IsDirFunc)(void*);
	typedef bool (MFSI_CALL* _HasChildFunc)(void*, const char*);

	typedef struct IMemoryPath (MFSI_CALL* _GetChildFunc)(void*, const char*);
	typedef void (MFSI_CALL* _GetChildsFunc)(void*, void*, IMemoryPathWriteCallBack);
	typedef void (MFSI_CALL* _GetAllFilesFunc)(void*, void*, IMemoryPathWriteCallBack);
	typedef void (MFSI_CALL* _DirDecFunc)(void*, bool);
	typedef struct IMemoryPath (MFSI_CALL* _CreatePathFunc)(void*, const char*);
	typedef bool (MFSI_CALL* _RemoveFileFunc)(void*);
	typedef bool (MFSI_CALL* _RemoveChildsFunc)(void*);
	typedef bool (MFSI_CALL* _RemoveSelfFunc)(void*);
	typedef bool (MFSI_CALL* _AddModeWriteFileFunc)(void*, const char*);

	struct IMemoryPath
	{
		void* _this;	// 原始对象指针 NULL值即不存在Path
		_ReadBytesFunc readBytes;
		_GetFileNameFunc getFileName;
		_GetPathFunc getPath;
		_WriteBytesFunc writeBytes;
		_IsFileFunc isFile;
		_IsDirFunc isDir;
		_ParentFunc parent;
		_HasChildFunc hasChild;
		_GetChildFunc getChild;
		// GET CHILDS应提供一个函数指针接收批量输入数据
		_GetChildsFunc getChilds;
		_GetAllFilesFunc getAllFiles;
		// dirDec用于强制声明该PATH是一个存在的文件夹 若不声明仅当存在子节点时视为目录存在
		_DirDecFunc dirDec;
		_CreatePathFunc createPath;
		_RemoveFileFunc removeFile;
		_RemoveChildsFunc removeChilds;
		_RemoveSelfFunc removeSelf;
		// 适用于文本文件的追加写入
		_AddModeWriteFileFunc addModeWriteFile;
	};
#ifdef __cplusplus
}

// 适用于CPP的视图包装
#include <iostream>
#include <vector>
#include <unordered_map>
#include <tuple>

namespace MFSI
{
	class MemoryBytesView
	{
	private:
		std::vector<char> bytes;
	public:
		MemoryBytesView(const IMemoryBytes iBytes): bytes(std::vector(iBytes.bytes, iBytes.bytes + iBytes.size))
		{
		}

		MemoryBytesView(const std::vector<char>& bytes)
		{
			this->bytes = bytes;
		}

		MemoryBytesView(const std::string& str)
		{
			std::vector<char> vec;
			for (char c : str)
			{
				vec.push_back(c);
			}
			bytes = vec;
		}

		MemoryBytesView(const char* str)
		{
			std::vector<char> vec;
			while (*str != '\0')
			{
				vec.push_back(*str);
				str++;
			}
			vec.push_back('\0');
			bytes = vec;
		}

		std::vector<char>& getVectorRef()
		{
			return bytes;
		}

		// 构造C结构体
		IMemoryBytes createCStruct() const
		{
			return IMemoryBytes{ (ByteSize)bytes.size(), bytes.data() };
		}
	};

	class MemoryPathView
	{
	private:
		const IMemoryPath _iPath;
	public:
		MemoryPathView(const IMemoryPath iPath) : _iPath(iPath) {
			if (iPath._this == NULL)
			{
				throw std::runtime_error("试图解析空的PATH结构");
			}
		}

		MemoryBytesView getBytesView() const
		{
			return _iPath.readBytes(_iPath._this);
		}

		std::string readText() const
		{
			auto bytes = getBytesView();
			auto& vcRef = bytes.getVectorRef();
			return std::string(vcRef.begin(), vcRef.end());
		}

		std::vector<char> getBytes() const
		{
			MemoryBytesView bs = getBytesView();
			return bs.getVectorRef();
		}

		std::string getPath() const
		{
			char buf[512]{};
			return std::string(_iPath.getPath(_iPath._this, buf));
		}

		std::string getFileName() const
		{
			return std::string(_iPath.getFileName(_iPath._this));
		}

		// 获取后缀名 如果存在(含.)
		std::string getExtension() const
		{
			std::string fileName = getFileName();
			size_t pos = fileName.rfind('.');
			if (pos == std::string::npos)
			{
				return "";
			}
			return fileName.substr(pos);
		}

		bool writeBytes(const MemoryBytesView& bytesView) const
		{
			IMemoryBytes datas = bytesView.createCStruct();
			return _iPath.writeBytes(_iPath._this, &datas);
		}

		bool writeTxt(const std::string& str) const
		{
			return writeBytes(str);
		}

		// 追加写入文本
		bool addTxt(const std::string& str) const
		{
			return _iPath.addModeWriteFile(_iPath._this, str.c_str());
		}
	
		// 批量文件写入
		void batchFilesWrite(const std::unordered_map<std::string, std::tuple<const void*, size_t>>& fileDatas) const
		{
			for (const auto& [key, value] : fileDatas)
			{
				if (std::get<0>(value) == nullptr || std::get<1>(value) < 0)
				{
					// 空文件
					createPath(key).writeTxt("");
					continue;
				}
				// 有数据的文件
				const unsigned char* datas = (const unsigned char*)std::get<0>(value);
				auto size = std::get<1>(value);
				std::vector<char> vcData(reinterpret_cast<const char*>(datas), reinterpret_cast<const char*>(datas) + size);
				createPath(key).writeBytes(vcData);
			}
		}

		MemoryPathView getChild(const std::string& path) const
		{
			return _iPath.getChild(_iPath._this, path.c_str());
		}

		bool isFile() const
		{
			return _iPath.isFile(_iPath._this);
		}

		bool isDir() const
		{
			return _iPath.isDir(_iPath._this);
		}

		bool hasChild(const std::string& childName) const
		{
			return _iPath.hasChild(_iPath._this, childName.c_str());
		}

		MemoryPathView getParent() const
		{
			return _iPath.parent(_iPath._this);
		}

		static void MFSI_CALL __C_GetChilds(void* out, IMemoryPath* data)
		{
			std::vector<MFSI::MemoryPathView>* obj = static_cast<std::vector<MFSI::MemoryPathView>*>(out);
			obj->push_back(*data);
		}

		std::vector<MemoryPathView> getChilds() const
		{
			std::vector<MemoryPathView> datas{};
			_iPath.getChilds(_iPath._this, &datas, __C_GetChilds);
			return datas;
		}

		std::vector<MemoryPathView> getAllFiles() const
		{
			std::vector<MemoryPathView> datas{};
			_iPath.getAllFiles(_iPath._this, &datas, __C_GetChilds);
			return datas;
		}

		void dirDec(bool state = true) const
		{
			_iPath.dirDec(_iPath._this, state);
		}

		MemoryPathView createPath(const std::string& pathName) const
		{
			return _iPath.createPath(_iPath._this, pathName.c_str());
		}

		bool removeFile() const
		{
			return _iPath.removeFile(_iPath._this);
		}

		bool removeChilds() const
		{
			return _iPath.removeChilds(_iPath._this);
		}

		bool removeSelf() const
		{
			return _iPath.removeSelf(_iPath._this);
		}
	};
}

#endif